/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @flow strict-local
 */
// 'use strict';
// import MiotAndroidScrollView from 'react-native/Libraries/Components/ScrollView/ScrollView'
//
// export default MiotAndroidScrollView
'use strict';
import {
  ScrollView,
  Platform,
  Animated,
  ColorPropType,
  EdgeInsetsPropType,
  PointPropType,
  StyleSheet,
  ViewPropTypes
} from 'react-native';
// const Animated = require('Animated');
// const ColorPropType = require('ColorPropType');
// const EdgeInsetsPropType = require('EdgeInsetsPropType');
// const PointPropType = require('PointPropType');
const PropTypes = require('prop-types');
const React = require('react');// const React = require('React');
const ReactNative = require('react-native');// const ReactNative = require('ReactNative');
import ScrollResponder from 'react-native/Libraries/Components/ScrollResponder';// const ScrollResponder = require('ScrollResponder');
import ScrollViewStickyHeader from 'react-native/Libraries/Components/ScrollView/ScrollViewStickyHeader';// const ScrollViewStickyHeader = require('ScrollViewStickyHeader');
// const StyleSheet = require('StyleSheet');
import StyleSheetPropType from 'react-native/Libraries/DeprecatedPropTypes/DeprecatedStyleSheetPropType';// const StyleSheetPropType = require('StyleSheetPropType');
import View from 'react-native/Libraries/Components/View/View';// const View = require('View');
// const ViewPropTypes = require('ViewPropTypes');
import ViewStylePropTypes from 'react-native/Libraries/DeprecatedPropTypes/DeprecatedViewStylePropTypes';// const ViewStylePropTypes = require('ViewStylePropTypes');
const createReactClass = require('create-react-class');
import dismissKeyboard from 'react-native/Libraries/Utilities/dismissKeyboard';// const dismissKeyboard = require('dismissKeyboard');
import flattenStyle from 'react-native/Libraries/StyleSheet/flattenStyle';// const flattenStyle = require('flattenStyle');
const invariant = require('fbjs/lib/invariant');
import processDecelerationRate from './DecelerationRate';
import requireNativeComponent from 'react-native/Libraries/ReactNative/requireNativeComponent';// const requireNativeComponent = require('requireNativeComponent');
/* $FlowFixMe(>=0.54.0 site=react_native_oss) This comment suppresses an error
 * found when Flow v0.54 was deployed. To see the error delete this comment and
 * run Flow. */
// const warning = require('fbjs/lib/warning');
import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource';// const resolveAssetSource = require('resolveAssetSource');
import type { NativeMethodsMixinType } from 'ReactNativeTypes';
import { referenceReport } from '../../../decorator/ReportDecorator';
/**
 * Component that wraps platform ScrollView while providing
 * integration with touch locking "responder" system.
 *
 * Keep in mind that ScrollViews must have a bounded height in order to work,
 * since they contain unbounded-height children into a bounded container (via
 * a scroll interaction). In order to bound the height of a ScrollView, either
 * set the height of the view directly (discouraged) or make sure all parent
 * views have bounded height. Forgetting to transfer `{flex: 1}` down the
 * view stack can lead to errors here, which the element inspector makes
 * easy to debug.
 *
 * Doesn't yet support other contained responders from blocking this scroll
 * view from becoming the responder.
 *
 *
 * `<ScrollView>` vs [`<FlatList>`](/react-native/docs/flatlist.html) - which one to use?
 *
 * `ScrollView` simply renders all its react child components at once. That
 * makes it very easy to understand and use.
 *
 * On the other hand, this has a performance downside. Imagine you have a very
 * long list of items you want to display, maybe several screens worth of
 * content. Creating JS components and native views for everything all at once,
 * much of which may not even be shown, will contribute to slow rendering and
 * increased memory usage.
 *
 * This is where `FlatList` comes into play. `FlatList` renders items lazily,
 * just when they are about to appear, and removes items that scroll way off
 * screen to save memory and processing time.
 *
 * `FlatList` is also handy if you want to render separators between your items,
 * multiple columns, infinite scroll loading, or any number of other features it
 * supports out of the box.
 */
// $FlowFixMe(>=0.41.0)
const MiotAndroidScrollView = createReactClass({
  displayName: 'MiotAndroidScrollView',
  propTypes: {
    ...ViewPropTypes,
    /**
         * Controls whether iOS should automatically adjust the content inset
         * for scroll views that are placed behind a navigation bar or
         * tab bar/ toolbar. The default value is true.
         * @platform ios
         */
    automaticallyAdjustContentInsets: PropTypes.bool,
    /**
         * The amount by which the scroll view content is inset from the edges
         * of the scroll view. Defaults to `{top: 0, left: 0, bottom: 0, right: 0}`.
         * @platform ios
         */
    contentInset: EdgeInsetsPropType,
    /**
         * Used to manually set the starting scroll offset.
         * The default value is `{x: 0, y: 0}`.
         * @platform ios
         */
    contentOffset: PointPropType,
    /**
         * When true, the scroll view bounces when it reaches the end of the
         * content if the content is larger then the scroll view along the axis of
         * the scroll direction. When false, it disables all bouncing even if
         * the `alwaysBounce*` props are true. The default value is true.
         * @platform ios
         */
    bounces: PropTypes.bool,
    /**
         * When true, gestures can drive zoom past min/max and the zoom will animate
         * to the min/max value at gesture end, otherwise the zoom will not exceed
         * the limits.
         * @platform ios
         */
    bouncesZoom: PropTypes.bool,
    /**
         * When true, the scroll view bounces horizontally when it reaches the end
         * even if the content is smaller than the scroll view itself. The default
         * value is true when `horizontal={true}` and false otherwise.
         * @platform ios
         */
    alwaysBounceHorizontal: PropTypes.bool,
    /**
         * When true, the scroll view bounces vertically when it reaches the end
         * even if the content is smaller than the scroll view itself. The default
         * value is false when `horizontal={true}` and true otherwise.
         * @platform ios
         */
    alwaysBounceVertical: PropTypes.bool,
    /**
         * When true, the scroll view automatically centers the content when the
         * content is smaller than the scroll view bounds; when the content is
         * larger than the scroll view, this property has no effect. The default
         * value is false.
         * @platform ios
         */
    centerContent: PropTypes.bool,
    /**
         * These styles will be applied to the scroll view content container which
         * wraps all of the child views. Example:
         *
         * ```
         * return (
         *   <ScrollView contentContainerStyle={styles.contentContainer}>
         *   </ScrollView>
         * );
         * ...
         * const styles = StyleSheet.create({
         *   contentContainer: {
         *     paddingVertical: 20
         *   }
         * });
         * ```
         */
    contentContainerStyle: StyleSheetPropType(ViewStylePropTypes),
    /**
         * A floating-point number that determines how quickly the scroll view
         * decelerates after the user lifts their finger. You may also use string
         * shortcuts `"normal"` and `"fast"` which match the underlying iOS settings
         * for `UIScrollViewDecelerationRateNormal` and
         * `UIScrollViewDecelerationRateFast` respectively.
         *
         *   - `'normal'`: 0.998 (the default)
         *   - `'fast'`: 0.99
         *
         * @platform ios
         */
    decelerationRate: PropTypes.oneOfType([
      PropTypes.oneOf(['fast', 'normal']),
      PropTypes.number
    ]),
    /**
         * When true, the scroll view's children are arranged horizontally in a row
         * instead of vertically in a column. The default value is false.
         */
    horizontal: PropTypes.bool,
    /**
         * The style of the scroll indicators.
         *
         *   - `'default'` (the default), same as `black`.
         *   - `'black'`, scroll indicator is black. This style is good against a light background.
         *   - `'white'`, scroll indicator is white. This style is good against a dark background.
         *
         * @platform ios
         */
    indicatorStyle: PropTypes.oneOf([
      'default', // default
      'black',
      'white'
    ]),
    /**
         * If sticky headers should stick at the bottom instead of the top of the
         * ScrollView. This is usually used with inverted ScrollViews.
         */
    invertStickyHeaders: PropTypes.bool,
    /**
         * When true, the ScrollView will try to lock to only vertical or horizontal
         * scrolling while dragging.  The default value is false.
         * @platform ios
         */
    directionalLockEnabled: PropTypes.bool,
    /**
         * When false, once tracking starts, won't try to drag if the touch moves.
         * The default value is true.
         * @platform ios
         */
    canCancelContentTouches: PropTypes.bool,
    /**
         * Determines whether the keyboard gets dismissed in response to a drag.
         *
         * *Cross platform*
         *
         *   - `'none'` (the default), drags do not dismiss the keyboard.
         *   - `'on-drag'`, the keyboard is dismissed when a drag begins.
         *
         * *iOS Only*
         *
         *   - `'interactive'`, the keyboard is dismissed interactively with the drag and moves in
         *     synchrony with the touch; dragging upwards cancels the dismissal.
         *     On android this is not supported and it will have the same behavior as 'none'.
         */
    keyboardDismissMode: PropTypes.oneOf([
      'none', // default
      'on-drag', // Cross-platform
      'interactive' // iOS-only
    ]),
    /**
         * Determines when the keyboard should stay visible after a tap.
         *
         *   - `'never'` (the default), tapping outside of the focused text input when the keyboard
         *     is up dismisses the keyboard. When this happens, children won't receive the tap.
         *   - `'always'`, the keyboard will not dismiss automatically, and the scroll view will not
         *     catch taps, but children of the scroll view can catch taps.
         *   - `'handled'`, the keyboard will not dismiss automatically when the tap was handled by
         *     a children, (or captured by an ancestor).
         *   - `false`, deprecated, use 'never' instead
         *   - `true`, deprecated, use 'always' instead
         */
    keyboardShouldPersistTaps: PropTypes.oneOf(['always', 'never', 'handled', false, true]),
    /**
         * When set, the scroll view will adjust the scroll position so that the first child that is
         * currently visible and at or beyond `minIndexForVisible` will not change position. This is
         * useful for lists that are loading content in both directions, e.g. a chat thread, where new
         * messages coming in might otherwise cause the scroll position to jump. A value of 0 is common,
         * but other values such as 1 can be used to skip loading spinners or other content that should
         * not maintain position.
         *
         * The optional `autoscrollToTopThreshold` can be used to make the content automatically scroll
         * to the top after making the adjustment if the user was within the threshold of the top before
         * the adjustment was made. This is also useful for chat-like applications where you want to see
         * new messages scroll into place, but not if the user has scrolled up a ways and it would be
         * disruptive to scroll a bunch.
         *
         * Caveat 1: Reordering elements in the scrollview with this enabled will probably cause
         * jumpiness and jank. It can be fixed, but there are currently no plans to do so. For now,
         * don't re-order the content of any ScrollViews or Lists that use this feature.
         *
         * Caveat 2: This simply uses `contentOffset` and `frame.origin` in native code to compute
         * visibility. Occlusion, transforms, and other complexity won't be taken into account as to
         * whether content is "visible" or not.
         *
         * @platform ios
         */
    maintainVisibleContentPosition: PropTypes.shape({
      minIndexForVisible: PropTypes.number.isRequired,
      autoscrollToTopThreshold: PropTypes.number
    }),
    /**
         * The maximum allowed zoom scale. The default value is 1.0.
         * @platform ios
         */
    maximumZoomScale: PropTypes.number,
    /**
         * The minimum allowed zoom scale. The default value is 1.0.
         * @platform ios
         */
    minimumZoomScale: PropTypes.number,
    /**
         * Called when the momentum scroll starts (scroll which occurs as the ScrollView glides to a stop).
         */
    onMomentumScrollBegin: PropTypes.func,
    /**
         * Called when the momentum scroll ends (scroll which occurs as the ScrollView glides to a stop).
         */
    onMomentumScrollEnd: PropTypes.func,
    /**
         * Fires at most once per frame during scrolling. The frequency of the
         * events can be controlled using the `scrollEventThrottle` prop.
         */
    onScroll: PropTypes.func,
    /**
         * Called when the user begins to drag the scroll view.
         */
    onScrollBeginDrag: PropTypes.func,
    /**
         * Called when the user stops dragging the scroll view and it either stops
         * or begins to glide.
         */
    onScrollEndDrag: PropTypes.func,
    /**
         * Called when scrollable content view of the ScrollView changes.
         *
         * Handler function is passed the content width and content height as parameters:
         * `(contentWidth, contentHeight)`
         *
         * It's implemented using onLayout handler attached to the content container
         * which this ScrollView renders.
         */
    onContentSizeChange: PropTypes.func,
    /**
         * When true, the scroll view stops on multiples of the scroll view's size
         * when scrolling. This can be used for horizontal pagination. The default
         * value is false.
         *
         * Note: Vertical pagination is not supported on Android.
         */
    pagingEnabled: PropTypes.bool,
    /**
         * When true, ScrollView allows use of pinch gestures to zoom in and out.
         * The default value is true.
         * @platform ios
         */
    pinchGestureEnabled: PropTypes.bool,
    /**
         * When false, the view cannot be scrolled via touch interaction.
         * The default value is true.
         *
         * Note that the view can always be scrolled by calling `scrollTo`.
         */
    scrollEnabled: PropTypes.bool,
    /**
         * This controls how often the scroll event will be fired while scrolling
         * (as a time interval in ms). A lower number yields better accuracy for code
         * that is tracking the scroll position, but can lead to scroll performance
         * problems due to the volume of information being send over the bridge.
         * You will not notice a difference between values set between 1-16 as the
         * JS run loop is synced to the screen refresh rate. If you do not need precise
         * scroll position tracking, set this value higher to limit the information
         * being sent across the bridge. The default value is zero, which results in
         * the scroll event being sent only once each time the view is scrolled.
         * @platform ios
         */
    scrollEventThrottle: PropTypes.number,
    /**
         * The amount by which the scroll view indicators are inset from the edges
         * of the scroll view. This should normally be set to the same value as
         * the `contentInset`. Defaults to `{0, 0, 0, 0}`.
         * @platform ios
         */
    scrollIndicatorInsets: EdgeInsetsPropType,
    /**
         * When true, the scroll view scrolls to top when the status bar is tapped.
         * The default value is true.
         * @platform ios
         */
    scrollsToTop: PropTypes.bool,
    /**
         * When true, shows a horizontal scroll indicator.
         * The default value is true.
         */
    showsHorizontalScrollIndicator: PropTypes.bool,
    /**
         * When true, shows a vertical scroll indicator.
         * The default value is true.
         */
    showsVerticalScrollIndicator: PropTypes.bool,
    /**
         * An array of child indices determining which children get docked to the
         * top of the screen when scrolling. For example, passing
         * `stickyHeaderIndices={[0]}` will cause the first child to be fixed to the
         * top of the scroll view. This property is not supported in conjunction
         * with `horizontal={true}`.
         */
    stickyHeaderIndices: PropTypes.arrayOf(PropTypes.number),
    /**
         * When set, causes the scroll view to stop at multiples of the value of
         * `snapToInterval`. This can be used for paginating through children
         * that have lengths smaller than the scroll view. Typically used in
         * combination with `snapToAlignment` and `decelerationRate="fast"` on ios.
         * Overrides less configurable `pagingEnabled` prop.
         *
         * Supported for horizontal scrollview on android.
         */
    snapToInterval: PropTypes.number,
    /**
         * When `snapToInterval` is set, `snapToAlignment` will define the relationship
         * of the snapping to the scroll view.
         *
         *   - `'start'` (the default) will align the snap at the left (horizontal) or top (vertical)
         *   - `'center'` will align the snap in the center
         *   - `'end'` will align the snap at the right (horizontal) or bottom (vertical)
         *
         * @platform ios
         */
    snapToAlignment: PropTypes.oneOf([
      'start', // default
      'center',
      'end'
    ]),
    /**
         * Experimental: When true, offscreen child views (whose `overflow` value is
         * `hidden`) are removed from their native backing superview when offscreen.
         * This can improve scrolling performance on long lists. The default value is
         * true.
         */
    removeClippedSubviews: PropTypes.bool,
    /**
         * The current scale of the scroll view content. The default value is 1.0.
         * @platform ios
         */
    zoomScale: PropTypes.number,
    /**
         * This property specifies how the safe area insets are used to modify the
         * content area of the scroll view. The default value of this property is
         * "never". Available on iOS 11 and later.
         * @platform ios
         */
    contentInsetAdjustmentBehavior: PropTypes.oneOf([
      'automatic',
      'scrollableAxes',
      'never', // default
      'always'
    ]),
    /**
         * A RefreshControl component, used to provide pull-to-refresh
         * functionality for the ScrollView. Only works for vertical ScrollViews
         * (`horizontal` prop must be `false`).
         *
         * See [RefreshControl](docs/refreshcontrol.html).
         */
    refreshControl: PropTypes.element,
    /**
         * Sometimes a scrollview takes up more space than its content fills. When this is
         * the case, this prop will fill the rest of the scrollview with a color to avoid setting
         * a background and creating unnecessary overdraw. This is an advanced optimization
         * that is not needed in the general case.
         * @platform android
         */
    endFillColor: ColorPropType,
    /**
         * Tag used to log scroll performance on this scroll view. Will force
         * momentum events to be turned on (see sendMomentumEvents). This doesn't do
         * anything out of the box and you need to implement a custom native
         * FpsListener for it to be useful.
         * @platform android
         */
    scrollPerfTag: PropTypes.string,
    /**
         * Used to override default value of overScroll mode.
         *
         * Possible values:
         *
         *  - `'auto'` - Default value, allow a user to over-scroll
         *    this view only if the content is large enough to meaningfully scroll.
         *  - `'always'` - Always allow a user to over-scroll this view.
         *  - `'never'` - Never allow a user to over-scroll this view.
         *
         * @platform android
         */
    overScrollMode: PropTypes.oneOf([
      'auto',
      'always',
      'never'
    ]),
    /**
         * When true, ScrollView will emit updateChildFrames data in scroll events,
         * otherwise will not compute or emit child frame data.  This only exists
         * to support legacy issues, `onLayout` should be used instead to retrieve
         * frame data.
         * The default value is false.
         * @platform ios
         */
    DEPRECATED_sendUpdatedChildFrames: PropTypes.bool,
    /**
         * Optionally an image can be used for the scroll bar thumb. This will
         * override the color. While the image is loading or the image fails to
         * load the color will be used instead. Use an alpha of 0 in the color
         * to avoid seeing it while the image is loading.
         *
         * - `uri` - a string representing the resource identifier for the image, which
         * should be either a local file path or the name of a static image resource
         * - `number` - Opaque type returned by something like
         * `import IMAGE from './image.jpg'`.
         * @platform vr
         */
    scrollBarThumbImage: PropTypes.oneOfType([
      PropTypes.shape({
        uri: PropTypes.string
      }),
      // Opaque type returned by import IMAGE from './image.jpg'
      PropTypes.number
    ]),
    /**
         * 吸附临界点
         * @platform android
         */
    snapHeight: PropTypes.number,
    /**
         *  吸附动画时间
         *  @platform android
         */
    scrollYDuration: PropTypes.number
  },
  mixins: [ScrollResponder.Mixin],
  _scrollAnimatedValue: (new Animated.Value(0): Animated.Value),
  _scrollAnimatedValueAttachment: (null: ?{detach: () => void}),
  _stickyHeaderRefs: (new Map(): Map<number, ScrollViewStickyHeader>),
  _headerLayoutYs: (new Map(): Map<string, number>),
  getInitialState: function() {
    return {
      ...this.scrollResponderMixinGetInitialState(),
      layoutHeight: null
    };
  },
  UNSAFE_componentWillMount: function() {
    this._scrollAnimatedValue = new Animated.Value(this.props.contentOffset ? this.props.contentOffset.y : 0);
    this._scrollAnimatedValue.setOffset(this.props.contentInset ? this.props.contentInset.top : 0);
    this._stickyHeaderRefs = new Map();
    this._headerLayoutYs = new Map();
    referenceReport('MiotAndroidScrollView', 'componentWillMount');
  },
  componentDidMount: function() {
    this._updateAnimatedNodeAttachment();
  },
  componentDidUpdate: function() {
    this._updateAnimatedNodeAttachment();
  },
  componentWillUnmount: function() {
    if (this._scrollAnimatedValueAttachment) {
      this._scrollAnimatedValueAttachment.detach();
    }
  },
  setNativeProps: function(props: Object) {
    this._scrollViewRef && this._scrollViewRef.setNativeProps(props);
  },
  /**
     * Returns a reference to the underlying scroll responder, which supports
     * operations like `scrollTo`. All ScrollView-like components should
     * implement this method so that they can be composed while providing access
     * to the underlying scroll responder's methods.
     */
  getScrollResponder: function(): ScrollView {
    return this;
  },
  getScrollableNode: function(): any {
    return ReactNative.findNodeHandle(this._scrollViewRef);
  },
  getInnerViewNode: function(): any {
    return ReactNative.findNodeHandle(this._innerViewRef);
  },
  /**
     * Scrolls to a given x, y offset, either immediately or with a smooth animation.
     *
     * Example:
     *
     * `scrollTo({x: 0, y: 0, animated: true})`
     *
     * Note: The weird function signature is due to the fact that, for historical reasons,
     * the function also accepts separate arguments as an alternative to the options object.
     * This is deprecated due to ambiguity (y before x), and SHOULD NOT BE USED.
     */
  scrollTo: function(
    y?: number | { x?: number, y?: number, animated?: boolean },
    x?: number,
    animated?: boolean
  ) {
    if (typeof y === 'number') {
      if (__DEV__ && console.warn) {
        console.warn('`scrollTo(y, x, animated)` is deprecated. Use `scrollTo({x: 5, y: 5, ' +
                'animated: true})` instead.');
      }
    } else {
      ({ x, y, animated } = y || {});
    }
    this.getScrollResponder().scrollResponderScrollTo(
      { x: x || 0, y: y || 0, animated: animated !== false }
    );
  },
  /**
     * If this is a vertical ScrollView scrolls to the bottom.
     * If this is a horizontal ScrollView scrolls to the right.
     *
     * Use `scrollToEnd({animated: true})` for smooth animated scrolling,
     * `scrollToEnd({animated: false})` for immediate scrolling.
     * If no options are passed, `animated` defaults to true.
     */
  scrollToEnd: function(
    options?: { animated?: boolean },
  ) {
    // Default to true
    const animated = (options && options.animated) !== false;
    this.getScrollResponder().scrollResponderScrollToEnd({
      animated: animated
    });
  },
  /**
     * Deprecated, use `scrollTo` instead.
     */
  scrollWithoutAnimationTo: function(y: number = 0, x: number = 0) {
    if (__DEV__ && console.warn) {
      console.warn('`scrollWithoutAnimationTo` is deprecated. Use `scrollTo` instead');
    }
    this.scrollTo({ x, y, animated: false });
  },
  /**
     * Displays the scroll indicators momentarily.
     *
     * @platform ios
     */
  flashScrollIndicators: function() {
    this.getScrollResponder().scrollResponderFlashScrollIndicators();
  },
  _getKeyForIndex: function(index, childArray) {
    const child = childArray[index];
    return child && child.key;
  },
  _updateAnimatedNodeAttachment: function() {
    if (this._scrollAnimatedValueAttachment) {
      this._scrollAnimatedValueAttachment.detach();
    }
    if (this.props.stickyHeaderIndices && this.props.stickyHeaderIndices.length > 0) {
      this._scrollAnimatedValueAttachment = Animated.attachNativeEvent(
        this._scrollViewRef,
        'onScroll',
        [{ nativeEvent: { contentOffset: { y: this._scrollAnimatedValue } } }]
      );
    }
  },
  _setStickyHeaderRef: function(key, ref) {
    if (ref) {
      this._stickyHeaderRefs.set(key, ref);
    } else {
      this._stickyHeaderRefs.delete(key);
    }
  },
  _onStickyHeaderLayout: function(index, event, key) {
    if (!this.props.stickyHeaderIndices) {
      return;
    }
    const childArray = React.Children.toArray(this.props.children);
    if (key !== this._getKeyForIndex(index, childArray)) {
      // ignore stale layout update
      return;
    }
    const layoutY = event.nativeEvent.layout.y;
    this._headerLayoutYs.set(key, layoutY);
    const indexOfIndex = this.props.stickyHeaderIndices.indexOf(index);
    const previousHeaderIndex = this.props.stickyHeaderIndices[indexOfIndex - 1];
    if (previousHeaderIndex != null) {
      const previousHeader = this._stickyHeaderRefs.get(
        this._getKeyForIndex(previousHeaderIndex, childArray)
      );
      previousHeader && previousHeader.setNextHeaderY(layoutY);
    }
  },
  _handleScroll: function(e: Object) {
    if (__DEV__) {
      if (this.props.onScroll && this.props.scrollEventThrottle == null && Platform.OS === 'ios') {
        console.log(
          'You specified `onScroll` on a <ScrollView> but not ' +
                    '`scrollEventThrottle`. You will only receive one event. ' +
                    'Using `16` you get all the events but be aware that it may ' +
                    'cause frame drops, use a bigger number if you don\'t need as ' +
                    'much precision.'
        );
      }
    }
    if (Platform.OS === 'android') {
      if (this.props.keyboardDismissMode === 'on-drag') {
        dismissKeyboard();
      }
    }
    this.scrollResponderHandleScroll(e);
  },
  _handleLayout: function(e: Object) {
    if (this.props.invertStickyHeaders) {
      this.setState({ layoutHeight: e.nativeEvent.layout.height });
    }
    if (this.props.onLayout) {
      this.props.onLayout(e);
    }
  },
  _handleContentOnLayout: function(e: Object) {
    const { width, height } = e.nativeEvent.layout;
    this.props.onContentSizeChange && this.props.onContentSizeChange(width, height);
  },
  _scrollViewRef: (null: ?ScrollView),
  _setScrollViewRef: function(ref: ?ScrollView) {
    this._scrollViewRef = ref;
  },
  _innerViewRef: (null: ?NativeMethodsMixinType),
  _setInnerViewRef: function(ref: ?NativeMethodsMixinType) {
    this._innerViewRef = ref;
  },
  render: function() {
    let useVerticalCustom = false;
    if (Platform.OS === 'android') {
      if (!this.props.horizontal) {
        useVerticalCustom = !!this.props.snapHeight;
      }
    }
    if (useVerticalCustom) {
      const contentContainerStyle = [
        this.props.contentContainerStyle
      ];
      let style, childLayoutProps;
      if (__DEV__ && this.props.style) {
        style = flattenStyle(this.props.style);
        childLayoutProps = ['alignItems', 'justifyContent']
          .filter((prop) => style && style[prop] !== undefined);
        invariant(
          childLayoutProps.length === 0,
          `ScrollView child layout (${ JSON.stringify(childLayoutProps)
          }) must be applied through the contentContainerStyle prop.`
        );
      }
      let contentSizeChangeProps = {};
      if (this.props.onContentSizeChange) {
        contentSizeChangeProps = {
          onLayout: this._handleContentOnLayout
        };
      }
      const { stickyHeaderIndices } = this.props;
      const hasStickyHeaders = stickyHeaderIndices && stickyHeaderIndices.length > 0;
      const childArray = hasStickyHeaders && React.Children.toArray(this.props.children);
      const children = hasStickyHeaders ?
        childArray.map((child, index) => {
          const indexOfIndex = child ? stickyHeaderIndices.indexOf(index) : -1;
          if (indexOfIndex > -1) {
            const key = child.key;
            const nextIndex = stickyHeaderIndices[indexOfIndex + 1];
            return (
              <ScrollViewStickyHeader
                key={key}
                ref={(ref) => this._setStickyHeaderRef(key, ref)}
                nextHeaderLayoutY={
                  this._headerLayoutYs.get(this._getKeyForIndex(nextIndex, childArray))
                }
                onLayout={(event) => this._onStickyHeaderLayout(index, event, key)}
                scrollAnimatedValue={this._scrollAnimatedValue}
                inverted={this.props.invertStickyHeaders}
                scrollViewHeight={this.state.layoutHeight}>
                {child}
              </ScrollViewStickyHeader>
            );
          } else {
            return child;
          }
        }) :
        this.props.children;
      const contentContainer =
                <View
                  {...contentSizeChangeProps}
                  ref={this._setInnerViewRef}
                  style={contentContainerStyle}
                  removeClippedSubviews={
                    // Subview clipping causes issues with sticky headers on Android and
                    // would be hard to fix properly in a performant way.
                    Platform.OS === 'android' && hasStickyHeaders ?
                      false :
                      this.props.removeClippedSubviews
                  }
                  collapsable={false}>
                  {children}
                </View>;
      const alwaysBounceVertical =
                this.props.alwaysBounceVertical !== undefined ?
                  this.props.alwaysBounceVertical :
                  !this.props.horizontal;
      const DEPRECATED_sendUpdatedChildFrames =
                !!this.props.DEPRECATED_sendUpdatedChildFrames;
      const baseStyle = styles.baseVertical;
      const props = {
        ...this.props,
        alwaysBounceVertical,
        style: ([baseStyle, this.props.style]: ?Array<any>),
        // Override the onContentSizeChange from props, since this event can
        // bubble up from TextInputs
        onContentSizeChange: null,
        onLayout: this._handleLayout,
        onMomentumScrollBegin: this.scrollResponderHandleMomentumScrollBegin,
        onMomentumScrollEnd: this.scrollResponderHandleMomentumScrollEnd,
        onResponderGrant: this.scrollResponderHandleResponderGrant,
        onResponderReject: this.scrollResponderHandleResponderReject,
        onResponderRelease: this.scrollResponderHandleResponderRelease,
        onResponderTerminate: this.scrollResponderHandleTerminate,
        onResponderTerminationRequest: this.scrollResponderHandleTerminationRequest,
        onScroll: this._handleScroll,
        onScrollBeginDrag: this.scrollResponderHandleScrollBeginDrag,
        onScrollEndDrag: this.scrollResponderHandleScrollEndDrag,
        onScrollShouldSetResponder: this.scrollResponderHandleScrollShouldSetResponder,
        onStartShouldSetResponder: this.scrollResponderHandleStartShouldSetResponder,
        onStartShouldSetResponderCapture: this.scrollResponderHandleStartShouldSetResponderCapture,
        onTouchEnd: this.scrollResponderHandleTouchEnd,
        onTouchMove: this.scrollResponderHandleTouchMove,
        onTouchStart: this.scrollResponderHandleTouchStart,
        onTouchCancel: this.scrollResponderHandleTouchCancel,
        scrollBarThumbImage: resolveAssetSource(this.props.scrollBarThumbImage),
        scrollEventThrottle: hasStickyHeaders ? 1 : this.props.scrollEventThrottle,
        sendMomentumEvents: (this.props.onMomentumScrollBegin || this.props.onMomentumScrollEnd) ?
          true : false,
        pagingEnabled: true,
        DEPRECATED_sendUpdatedChildFrames
      };
      const { decelerationRate } = this.props;
      if (decelerationRate) {
        props.decelerationRate = processDecelerationRate(decelerationRate);
      }
      const refreshControl = this.props.refreshControl;
      if (refreshControl) {
        if (Platform.OS === 'android') {
          // On Android wrap the ScrollView with a AndroidSwipeRefreshLayout.
          // Since the ScrollView is wrapped add the style props to the
          // AndroidSwipeRefreshLayout and use flex: 1 for the ScrollView.
          // Note: we should only apply props.style on the wrapper
          // however, the ScrollView still needs the baseStyle to be scrollable
          return React.cloneElement(
            refreshControl,
            { style: props.style },
            <AndroidScrollView {...props} style={baseStyle} ref={this._setScrollViewRef}>
              {contentContainer}
            </AndroidScrollView>
          );
        }
      }
      return (
        <AndroidScrollView {...props} ref={this._setScrollViewRef}>
          {contentContainer}
        </AndroidScrollView>
      );
    }
  }
});
const styles = StyleSheet.create({
  baseVertical: {
    flexGrow: 1,
    flexShrink: 1,
    flexDirection: 'column',
    overflow: 'scroll'
  },
  baseHorizontal: {
    flexGrow: 1,
    flexShrink: 1,
    flexDirection: 'row',
    overflow: 'scroll'
  },
  contentContainerHorizontal: {
    flexDirection: 'row'
  }
});
let nativeOnlyProps,
  AndroidScrollView;
if (Platform.OS === 'android') {
  nativeOnlyProps = {
    nativeOnly: {
      sendMomentumEvents: true
    }
  };
  AndroidScrollView = requireNativeComponent(
    'MIOTAndroidScrollView',
    (AndroidScrollView: React.ComponentType<any>),
    nativeOnlyProps
  );
}
export default MiotAndroidScrollView;